#ifndef MATH_3D_H
#define	MATH_3D_H
#include "VisioCommon.h"
#include <stdio.h>
#include <math.h>
#include <string>


struct Vector2i
{
    int x;
    int y;
};

struct Vector3f
{
    float x;
    float y;
    float z;

    Vector3f()
    {
    }

    Vector3f(float _x, float _y, float _z)
    {
        x = _x;
        y = _y;
        z = _z;
    }

    Vector3f Cross(const Vector3f& v) const;
	Vector3f& operator*= (const float scalar);
	Vector3f operator* (const float scalar) const;
	Vector3f operator+ (const Vector3f& rhs) const;
	Vector3f operator- (const Vector3f& rhs) const;
	Vector3f& operator+= (const Vector3f& rhs);
    Vector3f& Normalize();
	static Vector3f Min(const Vector3f& lhs, const Vector3f& rhs);
	static Vector3f Max( const Vector3f& lhs, const Vector3f& rhs );
	void Rotate(float Angle, const Vector3f& Axis);
	float Norm() const;
    void Print() const
    {
        printf("(%.02f, %.02f, %.02f", x, y, z);
    }
	
};



class Matrix4f
{
public:
    float m[4][4];

    Matrix4f()
    {        
    }


    inline void InitIdentity()
    {
        m[0][0] = 1.0f; m[0][1] = 0.0f; m[0][2] = 0.0f; m[0][3] = 0.0f;
        m[1][0] = 0.0f; m[1][1] = 1.0f; m[1][2] = 0.0f; m[1][3] = 0.0f;
        m[2][0] = 0.0f; m[2][1] = 0.0f; m[2][2] = 1.0f; m[2][3] = 0.0f;
        m[3][0] = 0.0f; m[3][1] = 0.0f; m[3][2] = 0.0f; m[3][3] = 1.0f;
    }

    inline Matrix4f operator*(const Matrix4f& Right) const
    {
        Matrix4f Ret;

        for (unsigned int i = 0 ; i < 4 ; i++) {
            for (unsigned int j = 0 ; j < 4 ; j++) {
                Ret.m[i][j] = m[i][0] * Right.m[0][j] +
                              m[i][1] * Right.m[1][j] +
                              m[i][2] * Right.m[2][j] +
                              m[i][3] * Right.m[3][j];
            }
        }

        return Ret;
    }

	inline Vector3f operator*(const Vector3f& rhs) const
	{
		Vector3f Ret;
		Ret.x = m[0][0] * rhs.x + m[0][1] * rhs.y  + m[0][2] * rhs.z + m[0][3];
		Ret.y = m[1][0] * rhs.x + m[1][1] * rhs.y  + m[1][2] * rhs.z + m[1][3];
		Ret.z = m[2][0] * rhs.x + m[2][1] * rhs.y  + m[2][2] * rhs.z + m[2][3];

		return Ret;
	}

    void InitScaleTransform(float ScaleX, float ScaleY, float ScaleZ);
    void InitRotateTransform(float RotateX, float RotateY, float RotateZ);
	void InitRotateTransform(Vector3f dir, float angle);
    void InitTranslationTransform(float x, float y, float z);
    void InitCameraTransform(const Vector3f& Target, const Vector3f& Up);
    void InitPersProjTransform(float FOV, float Width, float Height, float zNear, float zFar);
	static void PrintMat(const Matrix4f& m, std::string name = "");
};


class Quaternion
{
public:
    float x, y, z, w;

    Quaternion(float _x, float _y, float _z, float _w);

    void Normalize();

    Quaternion Conjugate();  

	
};

Quaternion operator*(const Quaternion& l, const Quaternion& r);

Quaternion operator*(const Quaternion& q, const Vector3f& v);

#endif	/* MATH_3D_H */

